package xj.graph2d.graph;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import xj.lang.CodeWriter;

public interface Subgraph <NodeType extends GraphNode<EdgeType>, 
			   EdgeType extends GraphEdge<NodeType>>
  extends GraphComponent {

  /**
   * return true if the specified node is added; return false if the
   * specified node already exist.
   */
  public boolean addNode(NodeType node);

  /**
   * return true if the specified node is removed; return false if the
   * specified node does not exist.
   */
  public boolean removeNode(NodeType node);

  public NodeType removeNode(String name);

  public boolean removeNode(NodeType node, boolean disconnect);

  public NodeType removeNode(String name, boolean disconnect);

  /**
   * return true if the specified edge is added; return false if the
   * specified edge already exist.
   */
  public boolean addEdge(EdgeType edge, boolean allowDuplicate);

  public boolean addEdge(EdgeType edge);

  /**
   * return true if the specified edge is removed; return false if the
   * specified edge does not exist.
   */
  public boolean removeEdge(EdgeType edge);

  public EdgeType removeEdge(String name);

  public NodeType disconnectDestination(EdgeType edge);

  public NodeType disconnectSource(EdgeType edge);

  public void connectDestination(EdgeType edge, NodeType node);

  public void connectSource(EdgeType edge, NodeType node);

  public void reverseEdgeDirection(EdgeType edge);

  public void moveEdgeToSubgraph(EdgeType e, Subgraph<NodeType, EdgeType> subg);

  public boolean isAllowDanglingEdges();

  public void setAllowDanglingEdges(boolean allowDanglingEdges);

  public boolean isAllowDuplicateEdges();

  public void setAllowDuplicateEdges(boolean allowDuplicateEdges);

  public void removeAllNodes();

  public int getNumberOfNodes();

  public int getNumberOfEdges();

  public boolean isEmpty();

  public boolean addSubgraph(Subgraph<NodeType, EdgeType> subg);

  public boolean removeSubgraph(Subgraph<NodeType, EdgeType> subg);

  public boolean removeSubgraph(String name);

  public boolean containsNode(NodeType node);

  public boolean containsEdge(EdgeType edge);

  public Set<NodeType> allSubnodes();

  public boolean containsSubnode(NodeType node);

  /**
   * Searches current subgraph for the node matching the supplied name.
   * 
   * @param name
   *                the name of the node to be found.
   * @return the Node matching the name or null, if there is no match.
   */
  public NodeType findNodeByName(String name);

  public NodeType findNodeByName(String name, boolean deep);

  /**
   * Searches current subgraph for the edge matching the supplied name.
   * 
   * @param name
   *                the name of the edge to be found.
   * @return the Edge matching the name or null, if there is no match.
   */
  public EdgeType findEdgeByName(String name);

  public EdgeType findEdgeByName(String name, boolean deep);

  /**
   * Searches current subgraph for the subgraph matching the supplied
   * name.
   * 
   * @param name
   *                the name of the subgraph to be found.
   * @return the Subgraph matching the name or null, if there is no match.
   */
  public Subgraph<NodeType, EdgeType> findSubgraphByName(String name);

  public Subgraph<NodeType, EdgeType> findSubgraphByName(String name, boolean deep);

  /*-
    ensures: 
    (result != null) =>
    (forall x in result @ x instanceof NodeType) 
    -*/
  public Iterator<NodeType> nodes();

  /*-
    ensures: 
    (result != null) => 
    (forall x in result @ x instanceof EdgeType) 
    -*/
  public Iterator<EdgeType> edges();

  public Iterator<Subgraph<NodeType, EdgeType>> subgraphs();

  public Set<NodeType> getNodeSet();

  public Set<EdgeType> getEdgeSet();

  public Set<Subgraph<NodeType, EdgeType>> getSubgraphSet();

  // public Iterator nodeSetIterator();

  /*-
    ensures: 
    (result != null) => 
    (forall x in result @ x instanceof EdgeType) 
    -*/
  public Set<EdgeType> leavingEdges(NodeType node);

  public Set<EdgeType> leavingEdges(NodeType node, int edgeType);

  /*-
    ensures: 
    (result != null) => 
    (forall x in result @ x instanceof EdgeType) 
    -*/
  public Set<EdgeType> arrivingEdges(NodeType node);

  public Set<EdgeType> arrivingEdges(NodeType node, int edgeType);

  public int getDegree(NodeType node);

  public int getInDegree(NodeType node);

  public int getOutDegree(NodeType node);

  public NodeType searchNode(Point2D p);

  public void move(double dx, double dy);

  public Rectangle2D getBounds();

  public void setNodeAttribute(String name, Object value);

  public void removeNodeAttribute(String name);

  public Object getNodeAttribute(String key);

  public void setEdgeAttribute(String name, Object value);

  public void removeEdgeAttribute(String name);

  public Object getEdgeAttribute(String key);

  /**
   * Prints an ascii description of each graph element to the supplied
   * stream.
   * 
   * @param output
   *                the OutputStream for writing the graph description.
   */
  public void printSubgraph(PrintWriter out);

  public void printSubgraph(int level);

  public void writeSubgraphXML(CodeWriter out, String namespacePrefix);

  public void buildSubgraphFromXML(org.w3c.dom.Node node, String namespaceURI,
				   Map<String, Object> compShapeMap);

}
